package hk.ust.comp3111.ustnutrition;

import hk.ust.comp3111.ustnutrition.data.DataAccessor;
import hk.ust.comp3111.ustnutrition.data.DataTableListener;
import hk.ust.comp3111.ustnutrition.data.db.IntakeRecord;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;

import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.ListFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MyHistoryFragment extends ListFragment implements DataTableListener<IntakeRecord>
{
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState)
	{
		View root = inflater.inflate(R.layout.my_history_frag, container, false);
		mDateBox = (TextView)root.findViewById(R.id.date_box);
		return root;
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		DataAccessor.Instance.getRecords().addChangeListener(this);
	}

	@Override
	public void onStop()
	{
		super.onStop();
		if (mDialog != null)
		{
			mDialog.dismiss();
			mDialog = null;
		}
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		DataAccessor.Instance.getRecords().removeChangeListener(this);
	}

	@Override
	public void onListItemClick(ListView l, View v, int position, long id)
	{
		List<IntakeRecord> data = mAdapter.getItem(position);
		if (data != null && !data.isEmpty())
		{
			AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
			FullAdapter adapter = new FullAdapter();
			adapter.addData(mAdapter.getItem(position));
			builder.setAdapter(adapter, null);
			mDialog = builder.create();
			mDialog.show();
		}
	}

	@Override
	public void onActivityCreated(Bundle savedInstanceState)
	{
		super.onActivityCreated(savedInstanceState);
		getListView().setDivider(null);
		getListView().setDividerHeight(0);

		mAdapter = new MyAdapter(getActivity());
		mEndDate = new Date();
		addNextData();
		addNextData();
		addNextData();
		setListAdapter(mAdapter);

		getListView().setOnScrollListener(new OnScrollListener()
				{
					@Override
					public void onScrollStateChanged(AbsListView view,
							int scrollState)
					{
						if (mIsShowDateBox)
						{
							if (scrollState == SCROLL_STATE_IDLE)
							{
								mDateBox.setVisibility(View.GONE);
								mIsShowDateBox = false;
							}
						}
						else
						{
							if (scrollState != SCROLL_STATE_IDLE)
							{
								mDateBox.setVisibility(View.VISIBLE);
								mIsShowDateBox = true;
							}
						}
					}

					@TargetApi(Build.VERSION_CODES.HONEYCOMB)
					@Override
					public void onScroll(AbsListView view, int firstVisibleItem,
							int visibleItemCount, int totalItemCount)
					{
						int dayDiff = (int)Math.ceil((totalItemCount
								- firstVisibleItem) / 24.0);
						Date d = new Date(mEndDate.getTime());
						GregorianCalendar cal = new GregorianCalendar();
						cal.setTime(d);
						cal.add(Calendar.DAY_OF_MONTH, dayDiff);
						mDateBox.setText(String.format("%d/%d",
								cal.get(Calendar.DAY_OF_MONTH),
								cal.get(Calendar.MONTH) + 1));
						if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
						{
							mDateBox.setY(firstVisibleItem
									/ (float)totalItemCount * view.getHeight());
						}

						if (firstVisibleItem == totalItemCount - visibleItemCount)
						{
							addNextData();
						}
					}

					private boolean mIsShowDateBox = false;
				});
	}
	
	boolean dirty;

	@Override
	public void changed(DataTableListener.ChangeEvent<IntakeRecord> event) {
		dirty = true;
		handler.postDelayed(new Runnable() {
			@Override
			public void run() {
				if(dirty) {
					dirty = false;
					if(mAdapter != null) {
						mAdapter.clear();
						mEndDate = new Date();
						addNextData();
						addNextData();
						addNextData();
					}
				}
			}
		}, 500);
	}

	private static class MyAdapter extends ArrayAdapter<List<IntakeRecord>>
	{
		public MyAdapter(Context context)
		{
			super(context, android.R.layout.simple_list_item_1);
			mInflater = LayoutInflater.from(context);
		}

		@SuppressWarnings("unused")
		public void setData(List<List<IntakeRecord>> items)
		{
			clear();
			addData(items);
		}

		public void addData(List<List<IntakeRecord>> items)
		{
			if (items != null)
			{
				for (List<IntakeRecord> r : items)
				{
					add(r);
				}
			}
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			HistoryItemView view = (HistoryItemView)convertView;
			if (view == null)
			{
				view = (HistoryItemView)mInflater.inflate(R.layout.history_item,
						parent, false);
			}

			List<IntakeRecord> item = getItem(position);
			if (item == null || item.isEmpty())
			{
				view.setActive(false);
				view.setTime(null);
				view.removeAllFoods();
			}
			else
			{
				view.setActive(true);
				view.setTime(item.get(0).getTime());
				view.removeAllFoods();
				for (IntakeRecord r : item)
				{
					view.addFood(r.getFood());
				}
			}
			return view;
		}

		private LayoutInflater mInflater;
	}

	private class FullAdapter extends ArrayAdapter<IntakeRecord>
	{
		public FullAdapter()
		{
			super(getActivity(), android.R.layout.simple_list_item_1);
			mInflater = LayoutInflater.from(getActivity());
		}

		public void addData(List<IntakeRecord> items)
		{
			if (items != null)
			{
				for (IntakeRecord r : items)
				{
					add(r);
				}
			}
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			FoodListCardView view = (FoodListCardView)convertView;
			if (view == null)
			{
				view = (FoodListCardView)mInflater.inflate(R.layout.food_list_card,
						parent, false);
			}

			IntakeRecord item = getItem(position);
			view.setFood(item.getFood());
			return view;
		}

		private LayoutInflater mInflater;
	}

	private void addNextData()
	{
		Iterator<IntakeRecord> rawIt = getIntakeRecords(mEndDate);
		List<List<IntakeRecord>> groups = groupRecords(rawIt);
		mAdapter.addData(groups);
		mEndDate.setTime(mEndDate.getTime() - (24 * 60 * 60 * 1000));
	}

	@SuppressWarnings("deprecation")
	private List<List<IntakeRecord>> groupRecords(Iterator<IntakeRecord> rawIt)
	{
		List<List<IntakeRecord>> product = new ArrayList<List<IntakeRecord>>(24);
		for (int i = 0; i < 24; ++i)
		{
			product.add(null);
		}
		while (rawIt.hasNext())
		{
			IntakeRecord ir = rawIt.next();
			int hour = ir.getTime().getHours();
			int pos = 23 - hour;
			if (product.get(pos) == null)
			{
				product.set(pos, new ArrayList<IntakeRecord>());
			}
			product.get(pos).add(ir);
		}
		return product;
	}

	private Iterator<IntakeRecord> getIntakeRecords(Date date)
	{
		return DataAccessor.Instance.getRecords().getQuery("byDate")
				.setKey(MiscUtils.getDate(date)).iterator();
	}

	private MyAdapter mAdapter;
	private Date mEndDate;
	private TextView mDateBox;
	private Dialog mDialog;

	private Handler handler = new Handler();
}
